package cn.edu.xust.communication.task;

import java.util.Date;

import cn.edu.xust.Ro.MulHotelEleRo;
import cn.edu.xust.Ro.MulHotelWtRo;
import cn.edu.xust.communication.MyAmmeterReader;
import cn.edu.xust.communication.MyWaterReader;
import cn.edu.xust.communication.model.Result;
import cn.edu.xust.configuration.exception.Default200Exception;
import cn.edu.xust.configuration.exception.ErrorConstant;
import cn.edu.xust.entity.*;
import cn.edu.xust.service.*;
import cn.edu.xust.util.EmailSendUtil;
import cn.edu.xust.util.R;
import cn.edu.xust.util.ruoyi.StringUtils;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.util.DateUtils;
import io.github.biezhi.ome.SendMailException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author ufo
 * @Description
 * @Date 2021/3/1 10:04
 * @Version 1.0
 */


@Slf4j
@EnableScheduling
@Configuration
@Lazy(false)
public class TaskList {

    @Resource
    DeviceService deviceService;
    @Resource
    GatewayService gatewayService;
    @Autowired
    private ElecdataService elecdatas;
    @Resource
    CollectlogService collectlogService;
    @Resource
    EmailSendUtil emailSendUtil;
    @Autowired
    private WtdataService wtdataService;
    @Autowired
    private HotelService hotelService;

    /**
     * 读表
     */
    @Async("asyncServiceExecutor")
    public void readdevicedata(String timetype) {
        try {
            //停留20秒，等待网关连接  下次更新
            Thread.sleep(20 * 1000);
        } catch (InterruptedException e) {
            log.warn(String.valueOf(e));
        }
        ArrayList<String> list = new ArrayList<>();
        //只查这两个酒店
        list.add("1");
        list.add("1002");

        //拿到所有设备
        List<DeviceEntity> deviceEntities = deviceService.getByHotels(list);
        deviceEntities.sort((o1, o2) -> {
            int hotelIdComparison = Integer.compare(o1.getHotelid(), o2.getHotelid());
            if (hotelIdComparison != 0) {
                return hotelIdComparison;
            } else {
                return o1.getRoomname().compareTo(o2.getRoomname());
            }
        });

        //拿到设备需要的网关id  这里需要注意 定时任务较长，网关地址可能发生改变
        List<Integer> gatewayidlist = deviceEntities.stream()
                .map(DeviceEntity::getGatewayid)
                .distinct()
                .collect(Collectors.toList());

        //拿到需要的网关
        List<GatewayEntity> gatewayEntities = gatewayService.listByIds(gatewayidlist);
        Map<Integer, GatewayEntity> gatewayneed = gatewayEntities.stream()
                .collect(Collectors.toMap(GatewayEntity::getId, gatewayEntity -> gatewayEntity));

        int i = 1;
        //当前时间
        long first = System.currentTimeMillis();
        long now = System.currentTimeMillis();
        //开始对每个设备读取
        for (DeviceEntity deviceEntity : deviceEntities) {

            //每60秒刷新一次网关ip
            long doing = System.currentTimeMillis();
            log.info("已耗时{}秒", (doing - now) / 1000);
            if (doing - first >= 60 * 1000) {
                log.info("============每一分钟:刷新网关缓存:防止此次任务网关地址发生改变而读取不到  ============");
                first = doing;
                gatewayEntities = gatewayService.listByIds(gatewayidlist);
                gatewayneed = gatewayEntities.stream()
                        .collect(Collectors.toMap(GatewayEntity::getId, gatewayEntity -> gatewayEntity));
            }

            String devicename = deviceEntity.getName();

            log.info("============:定时读取:第{}/{}台设备:{}============", i++, deviceEntities.size(), devicename);
            boolean valid = validdevivce(deviceEntity);
            if (!valid) {
                log.info("device实体缺少参数,skip");
                continue;
            }
            Integer gatewayid = deviceEntity.getGatewayid();

            //记录查询结果
            CollectlogEntity collectlog = new CollectlogEntity();
            collectlog.setCt(new Date());
            collectlog.setDevicename(devicename);
            collectlog.setHotelid(deviceEntity.getHotelid());
            collectlog.setRoomname(deviceEntity.getRoomname());

            //拿到网关
            GatewayEntity gat = gatewayneed.get(gatewayid);
            //拿到ip通道
            String ip = gat.getIp();

            //ip通道空-网关不在线
            if (ip.equals("OFFLINE") || ip.isEmpty()) {
                log.info("该设备的配置的网关不在线{}", devicename);
                //记录进日志
                if ("ele".equals(deviceEntity.getType())) {
                    collectlog.setTaskname("定时读电表");
                } else {
                    collectlog.setTaskname("定时读水表");
                }
                collectlog.setState("0");
                collectlog.setMsg("网关不在线" + gatewayid);
                collectlogService.save(collectlog);
                //发送错误邮件通知
                try {
                    emailSendUtil.sendMailForPmsError(collectlog.toString(), "网关不在线");
                } catch (SendMailException e) {
                    log.warn("邮件发送失败");
                }
            } else {
                if ("ele".equals(deviceEntity.getType())) {
                    log.info("定时读电表:{}", devicename);
                    collectlog.setTaskname("定时读电表");
                    MyAmmeterReader reader2 = new MyAmmeterReader(ip, devicename);
                    //查询电表
                    ElecdataEntity elecdataEntity = null;
                    try {
                        elecdataEntity = reader2.readAll(deviceEntity);
                    } catch (Exception e) {
                        log.info("定时读电表:{}:失败", devicename);
                    }
                    //加上日期类型
                    if (elecdataEntity != null) {
                        elecdataEntity.setTimetype(timetype);
                    }
                    //如果是每日查询 则加上日期flag
                    if ("day".equals(timetype)) {
                        if (elecdataEntity != null) {
                            elecdataEntity.setTimetypeflag(DateUtils.format(new Date(), "yyyy-MM-dd"));
                        }
                    }
                    //解析结果不是空就存入数据库
                    if (elecdataEntity != null && elecdataEntity.getVoltage() != null && !elecdataEntity.getElecwattage().equals("null")) {
                        elecdatas.save(elecdataEntity);
                    }
                } else {
                    log.info("定时读水表:{}", devicename);
                    MyWaterReader reader = new MyWaterReader(deviceEntity, ip);
                    //水表
                    Result result = null;
                    try {
                        result = reader.readAll();
                    } catch (Default200Exception e) {
                        log.info("定时读水表:{}:失败", devicename);
                    }
                    //水表错误记录下来
                    if (result != null && (0 == result.getCode() || 2 == result.getCode())) {
                        collectlog.setTaskname("定时读水表");
                        collectlog.setState("0");
                        collectlog.setMsg(result.getMessage());
                        collectlogService.save(collectlog);
                    }
                    //解析数据出来 并持久化到数据库中
                    try {
                        if (result != null) {
                            deviceService.parsePersistwt(result.getMessage(), timetype);
                        }
                    } catch (Default200Exception e) {
                        log.info("定时读水表:{}:失败", devicename);
                    }
                }
            }
            try {
                //停留三秒，下次更新
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        log.info("结束子线程任务");
    }

    boolean validdevivce(DeviceEntity deviceEntity) {

        String name = deviceEntity.getName();
        String nickname = deviceEntity.getNickname();
        String type = deviceEntity.getType();
        Integer gatewayid = deviceEntity.getGatewayid();
        Integer hotelid = deviceEntity.getHotelid();
        String roomname = deviceEntity.getRoomname();
        String classify = deviceEntity.getClassify();
        return !StringUtils.isEmpty(name)
                && !StringUtils.isEmpty(nickname)
                && !StringUtils.isEmpty(type)
                && !StringUtils.isEmpty(gatewayid + "")
                && !StringUtils.isEmpty(hotelid + "")
                && !StringUtils.isEmpty(roomname)
                && !StringUtils.isEmpty(classify);
    }

    public void checkCaiji() throws SendMailException {

        log.info("定时检查数量");
        //检查水表数量
        String date = DateUtil.format(new Date(), "yyyy-MM-dd");
        String hotelid = "1002";


        //正常数量
        List<DeviceEntity> eles = deviceService.getByHotelAndType(hotelid, "ele");
        List<DeviceEntity> coldwts = deviceService.getByHotelAndType(hotelid, "coldwt");
        List<DeviceEntity> hotwts = deviceService.getByHotelAndType(hotelid, "hotwt");

        List<MulHotelEleRo> ele = elecdatas.getByHType(hotelid, "ele", date);
        List<MulHotelWtRo> coldwt = wtdataService.getByHType(hotelid, "coldwt", date);
        List<MulHotelWtRo> hotwt = wtdataService.getByHType(hotelid, "hotwt", date);


        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("电表：配置"+eles.size()+"台，采集"+ele.size()+"台\n");
        stringBuffer.append("冷水：配置"+coldwts.size()+"台，采集"+coldwt.size()+"台\n");
        stringBuffer.append("热水：配置"+hotwts.size()+"台，采集"+hotwt.size()+"台\n");

        boolean needsend = false;


        if (eles.size() != ele.size()) {
            needsend = true;
            stringBuffer.append("\n电表未匹配房号：\n");


            // 提取ele中的房间号
            Set<String> eleRoomNames = new HashSet<>();
            for (MulHotelEleRo item : ele) {
                eleRoomNames.add(item.getRoomname());
            }

            // 提取eles中的房间号
            Set<String> elesRoomNames = new HashSet<>();
            for (DeviceEntity item : eles) {
                elesRoomNames.add(item.getRoomname());
            }

            // 找出eles中不存在于ele的房间号
            elesRoomNames.removeAll(eleRoomNames);

            // 根据这些房间号，从eles中找到对应的DeviceEntity对象
            for (DeviceEntity item : eles) {
                if (elesRoomNames.contains(item.getRoomname())) {
                    stringBuffer.append(item.getRoomname()).append(":").append(item.getName()).append("\n");
                }
            }
        }


        if (coldwt.size() != coldwts.size()) {
            needsend = true;
            stringBuffer.append("\n冷表未匹配房号：\n");


            // 提取ele中的房间号
            Set<String> eleRoomNames = new HashSet<>();
            for (MulHotelWtRo item : coldwt) {
                eleRoomNames.add(item.getRoomname());
            }

            // 提取eles中的房间号
            Set<String> elesRoomNames = new HashSet<>();
            for (DeviceEntity item : coldwts) {
                elesRoomNames.add(item.getRoomname());
            }

            // 找出eles中不存在于ele的房间号
            elesRoomNames.removeAll(eleRoomNames);

            // 根据这些房间号，从eles中找到对应的DeviceEntity对象
            for (DeviceEntity item : coldwts) {
                if (elesRoomNames.contains(item.getRoomname())) {
                    stringBuffer.append(item.getRoomname()).append(":").append(item.getName()).append("\n");
                }
            }

        }


        if (hotwt.size() != hotwts.size()) {
            needsend = true;
            stringBuffer.append("\n热表未匹配房号：\n");

            // 提取ele中的房间号
            Set<String> eleRoomNames = new HashSet<>();
            for (MulHotelWtRo item : hotwt) {
                eleRoomNames.add(item.getRoomname());
            }

            // 提取eles中的房间号
            Set<String> elesRoomNames = new HashSet<>();
            for (DeviceEntity item : hotwts) {
                elesRoomNames.add(item.getRoomname());
            }

            // 找出eles中不存在于ele的房间号
            elesRoomNames.removeAll(eleRoomNames);

            // 根据这些房间号，从eles中找到对应的DeviceEntity对象
            for (DeviceEntity item : hotwts) {
                if (elesRoomNames.contains(item.getRoomname())) {
                    stringBuffer.append(item.getRoomname()).append(":").append(item.getName()).append("\n");
                }
            }
        }
        stringBuffer.append("\n\n\n 您可通过点击 http://www.xiaozhuiot.cn/xz/easycheck/checknum  再次查询");
//        stringBuffer.append("\n\n\n 说明：每日电表是在22:30-04:30中取最大id的值，每日水表同上。");

        if (needsend) {
            emailSendUtil.sendMail(stringBuffer.toString(), "采集数量异常，请及时检查");
        }
    }
}


